package com.flying.fish.gateway.component.groovy;
 
import com.flying.fish.formwork.base.BaseGroovyService;
import com.flying.fish.formwork.entity.RegServer;
import com.flying.fish.formwork.service.RegServerService;
import com.flying.fish.formwork.util.NetworkIpUtils;
import org.apache.commons.lang3.*;
import org.slf4j.*;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.security.MessageDigest;
import java.util.Map;
import java.nio.charset.StandardCharsets;

/**
 * @Description
 * @Author admin
 * @Version V1.0
*/
public class ParameterGroovyService extends BaseGroovyService {

    private static final String APP_SECRET = "8898";

    @Resource
    private RegServerService regServerService;

    private Logger log = LoggerFactory.getLogger("ParameterGroovyService");
    @Override
    public void apply(ServerWebExchange exchange) throws Exception {
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = exchange.getRequest().getHeaders();
        String remoteAddr = NetworkIpUtils.getIpAddress(request);
        
        //routeId, ruleName, extednInfo从继承父类BaseGroovyService中获取
        log.info("网关路由【{}】执行GroovySrcipt规则引擎动态脚本组件名称【{}】,扩展参数【{}】", routeId, ruleName, extednInfo);
        
        ///////////////////////////////参数检查/////////////////////////////////
        Map<String,String> valueMap = request.getQueryParams().toSingleValueMap();
        //checkParam(request, "userId");
        String clientId = checkAndGetHeader(request, "x-jade-paasid");
        String timestamp = checkAndGetHeader(request, "x-jade-timestamp");
        String nonce = checkAndGetHeader(request, "x-jade-nonce");
        String signature = checkAndGetHeader(request, "x-jade-signature");

        ///////////////////////////////规则校验/////////////////////////////////
        String secret = ParameterGroovyService.APP_SECRET;
        secret = getSecretKey(clientId, routeId);
        String signServer = generateSignature(timestamp, secret, nonce);
        if (!StringUtils.equalsIgnoreCase(signature, signServer)) {
            log.info("签名不一致!客户端签名【{}】服务端签名【{}】", signature, signServer);
            throw new IllegalArgumentException("签名不一致");
        }
    }

    private String getSecretKey(String clientId, String routeId) {
        RegServer regServer = regServerService.getByClientIdAndRouteId(clientId, routeId);
        if (ObjectUtils.isEmpty(regServer)) {
            log.info("客户端未注册!客户端id【{}】routeId【{}】", clientId, routeId);
            throw new IllegalArgumentException("客户端未注册");
        }
        String secretKey = regServer.getSecretKey();
        if (ObjectUtils.isEmpty(secretKey)) {
            secretKey = clientId;
        }
        return secretKey;
    }

    private String checkAndGetHeader(ServerHttpRequest request, String param) throws Exception {
        // 获取请求头中的所有头信息
        HttpHeaders headers = request.getHeaders();
        // 获取请求头中的token
        String paramValue= headers.getFirst(param);
        Map<String,String> valueMap = request.getQueryParams().toSingleValueMap();
        if (StringUtils.isBlank(paramValue)){
            throw new IllegalArgumentException(String.format("缺少%s请求头", param));
        }
        return paramValue;
    }

    private String generateSignature(String timestamp, String secret, String nonce) throws Exception {
        String message = String.format("%s%s%s%s", timestamp, secret, nonce, timestamp);
        log.info("签名串【{}】", message);
        try {
            //byte[] hash = DigestUtils.sha256(message);

            MessageDigest digest = MessageDigest.getInstance("SHA-256");  
            byte[] encodedhash = digest.digest(message.getBytes(StandardCharsets.UTF_8));  
            String sha256Hash = bytesToHex(encodedhash);

            return sha256Hash.toUpperCase();
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate SHA-256 signature", e);
        }
    }

    private String bytesToHex(byte[] hash) {  
        StringBuilder hexString = new StringBuilder(2 * hash.length);  
        for (int i = 0; i < hash.length; i++) {  
            String hex = Integer.toHexString(0xff & hash[i]);  
            if(hex.length() == 1) {  
                hexString.append('0');  
            }  
            hexString.append(hex);  
        }  
        return hexString.toString();  
    } 
}